package com.example.prom.qianduoduo.y2025.controller;

import com.alibaba.fastjson.JSON;
import com.example.prom.qianduoduo.y2025.model.SacinfoModel;
import com.example.prom.strategy.excel.CustomCellStyleStrategy;
import com.example.prom.strategy.excel.CustomColumnWidthStrategy;
import com.example.prom.utils.DateUtil;
import com.example.prom.utils.HttpClientSingleton;
import com.example.prom.utils.HttpNewUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import static com.alibaba.excel.EasyExcelFactory.write;

/**
 * Description
 *
 * @author DangWen
 */
public class SacinfoTest {
    private static final int THREAD_COUNT = 5; // 使用10个线程并行抓取
    private static final int BATCH_SIZE = 100; // 每次写入Excel的数据批次大小
    private static final String BASE_URL = "https://dbba.sacinfo.org.cn/";
    private static final ConcurrentLinkedQueue<SacinfoModel> resultQueue = new ConcurrentLinkedQueue<>();
    private static final Semaphore rateLimiter = new Semaphore(5); // 控制请求频率
    private static final int RATE_LIMIT_DELAY = 1000; // 请求间隔时间（毫秒）
    private static final String EXCEL_PATH = "D:\\workspace-pycharm\\spider-out\\123.xlsx"; // Excel文件路径
    private static volatile boolean isExcelInitialized = false;
    private static final Object excelLock = new Object();

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(THREAD_COUNT);
        CountDownLatch completionLatch = new CountDownLatch(THREAD_COUNT);
        AtomicInteger currentPage = new AtomicInteger(1);
        int totalPages = 10; // 总共785页

        // 启动写入线程
        Thread writerThread = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    List<SacinfoModel> batchToWrite = new ArrayList<>();
                    while (batchToWrite.size() < BATCH_SIZE) {
                        SacinfoModel model = resultQueue.poll();
                        if (model != null) {
                            batchToWrite.add(model);
                        } else {
                            if (completionLatch.getCount() == 0 && resultQueue.isEmpty()) {
                                // 如果所有任务完成且队列为空，最后一次写入
                                if (!batchToWrite.isEmpty()) {
                                    exportExcelBatch(batchToWrite);
                                }
                                return;
                            }
                            Thread.sleep(RATE_LIMIT_DELAY);
                        }
                    }
                    exportExcelBatch(batchToWrite);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        });
        writerThread.start();

        // 提交爬虫任务
        for (int i = 0; i < THREAD_COUNT; i++) {
            executorService.submit(() -> {
                try {
                    WebDriver webDriver = getWebDriver();
                    WebDriverWait wait = new WebDriverWait(webDriver, Duration.ofSeconds(30));
                    HttpClient httpClient = HttpClientSingleton.getLongCustomHttpClient();
                    Map<String, String> headers = getHeaders();

                    while (true) {
                        int page = currentPage.getAndIncrement(); // 原子操作获取页码
                        if (page > totalPages) {
                            break;
                        }

                        try {
                            // 控制请求频率
                            rateLimiter.acquire();
                            try {
                                processPage(page, httpClient, headers, webDriver, wait);
                            } finally {
                                Thread.sleep(RATE_LIMIT_DELAY);
                                rateLimiter.release();
                            }
                        } catch (Exception e) {
                            System.err.println("Error processing page " + page + ": " + e.getMessage());
                        }
                    }
                    webDriver.quit();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    completionLatch.countDown();
                }
            });
        }

        try {
            completionLatch.await();
            writerThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            executorService.shutdown();
        }
    }

    private static Map<String, String> getHeaders() {
        Map<String, String> headers = new HashMap<>();
        headers.put("Accept-Language", "zh-CN,zh;q=0.9");
        headers.put("Cookie", "Hm_lvt_36f2f0446e1c2cda8410befc24743a9b=1751339940,1751416952,1751419643; HMACCOUNT=8134B8F59C308B5F; Hm_lpvt_36f2f0446e1c2cda8410befc24743a9b=1751420045");
        headers.put("Accept-Encoding", "gzip, deflate, br, zstd");
        headers.put("Referer", "https://dbba.sacinfo.org.cn/stdList");
        headers.put("Accept", "application/json, text/javascript, */*; q=0.01");
        headers.put("Content-Type", "application/x-www-form-urlencoded");
        headers.put("X-Requested-With", "XMLHttpRequest");
        headers.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36");
        headers.put("Connection", "keep-alive");
        return headers;
    }

    private static void processPage(int page, HttpClient httpClient, Map<String, String> headers, WebDriver webDriver, WebDriverWait wait) throws Exception {
        System.out.println("Processing page: " + page);
        Map<String, String> queryMap = new HashMap<>();
        queryMap.put("current", String.valueOf(page));
        queryMap.put("size", "100");
        queryMap.put("status", "现行");

        HttpResponse httpResponse = HttpNewUtils.doPostByApplicationJson(
                BASE_URL + "stdQueryList",
                null,
                httpClient,
                headers,
                queryMap,
                JSON.toJSONString(queryMap)
        );

        String result = EntityUtils.toString(httpResponse.getEntity(), "UTF-8");
        Map resultMap = (Map) JSON.parse(result);
        Object records = resultMap.get("records");
        List<SacinfoModel> queryResultList = JSON.parseArray(records.toString(), SacinfoModel.class);

        for (SacinfoModel sacinfoModel : queryResultList) {
            processModel(sacinfoModel, webDriver, wait);
            resultQueue.offer(sacinfoModel);
        }
    }

    private static void processModel(SacinfoModel sacinfoModel, WebDriver webDriver, WebDriverWait wait) throws Exception {
        sacinfoModel.setActDateStr(DateUtil.formatTimeStamp(sacinfoModel.getActDate()));
        sacinfoModel.setIssueDateStr(DateUtil.formatTimeStamp(sacinfoModel.getIssueDate()));
        sacinfoModel.setRecordDateStr(DateUtil.formatTimeStamp(sacinfoModel.getRecordDate()));

        String detailPage = BASE_URL + "stdDetail/" + sacinfoModel.getPk();
        webDriver.get(detailPage);
        wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector(".main-body")));

        String pageSource = webDriver.getPageSource();
        Document document = Jsoup.parse(pageSource);
        String industryClassification = document.selectFirst("dt:contains(行业分类) + dd").text().trim();
        sacinfoModel.setIndustryClassification(industryClassification);

        Thread.sleep(500 + new Random().nextInt(500));
    }

    private static synchronized void exportExcelBatch(List<SacinfoModel> batch) {
        try {
            // 去重
            List<SacinfoModel> uniqueBatch = batch.stream()
                    .collect(Collectors.collectingAndThen(
                            Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(SacinfoModel::getPk))),
                            ArrayList::new
                    ));

            synchronized (excelLock) {
                if (!isExcelInitialized) {
                    // 第一次写入 - 创建新文件并包含表头
                    write(EXCEL_PATH, SacinfoModel.class)
                            .sheet()
                            .head(SacinfoModel.class)
                            .registerWriteHandler(new CustomColumnWidthStrategy())
                            .registerWriteHandler(new CustomCellStyleStrategy())
                            .doWrite(uniqueBatch);
                    isExcelInitialized = true;
                } else {
                    // 追加写入现有文件
                    write(EXCEL_PATH, SacinfoModel.class)
                            .sheet()
                            .registerWriteHandler(new CustomColumnWidthStrategy())
                            .registerWriteHandler(new CustomCellStyleStrategy())
                            .doWrite(uniqueBatch);
                }
            }
        } catch (Exception e) {
            System.err.println("Error writing to Excel: " + e.getMessage());
        }
    }

    public static WebDriver getWebDriver(){
        Path path = Paths.get("00dowin/src/main/resources/static/chromedriver.exe");
        System.setProperty("webdriver.chrome.driver", String.valueOf(path.toAbsolutePath()));
        ChromeOptions options = new ChromeOptions();
        // 基础设置
        options.addArguments(
                "--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
                "--window-size=1920,1080",
                "--lang=zh-CN,zh;q=0.9",
                "--disable-gpu",
                "--disable-blink-features=AutomationControlled",
                "--remote-allow-origins=*",
                "--disable-web-security",
                "--allow-running-insecure-content",
                "--disable-extensions",
                "--no-sandbox"
        );

        // 禁用自动化特征
        options.setExperimentalOption("excludeSwitches", Arrays.asList(
                "enable-automation",
                "load-extension",
                "enable-logging"
        ));
        options.setExperimentalOption("useAutomationExtension", false);
        // 创建WebDriver实例
        return new ChromeDriver(options);
    }
}
